package com.youlin.untils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.youlin.config.CenterConfig;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 微信小程序工具
 */
@Component
public class WxSecCheckUtil {

    @Autowired
    private OSSUtil ossUtil;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private CenterConfig centerConfig;

    // String[0-WxActive, 1-AppId, 2-Secret]
    public String[] getWxParam() {
        // 首先获取远程配置中心配置
        String wxActive = centerConfig.getActive();
        String appId = centerConfig.getAppId();
        String secret = centerConfig.getSecret();
        if (StringUtils.isNotBlank(wxActive) && StringUtils.isNotBlank(appId)
                && StringUtils.isNotBlank(secret) && appId.contains(wxActive)) {
            return new String[]{wxActive, appId, secret};
        }

        // 其次获取本地配置(Redis缓存)
        if (StringUtils.isBlank(wxActive)) wxActive = RedisUtil
                .getObject(redisTemplate, MyEnum.WX_ACTIVE.getMessage(), String.class);
        Map<String, String> app = (Map<String, String>)
                redisTemplate.opsForHash().get(MyEnum.WX_APPLETS.getMessage(), wxActive);
        appId = app.get("appId");
        secret = app.get("secret");
        return new String[]{wxActive, appId, secret};
    }

    public String getAccessTokenFromRedis() {
        String access_token = RedisUtil.getObject(redisTemplate, MyEnum.ACCESS_TOKEN_KEY.getMessage(), String.class);
        if (StringUtils.isEmpty(access_token)) {
            RLock rLock = redissonClient.getLock("ACCESS_TOKEN_LOCK");
            try {
                rLock.lock();
                access_token = RedisUtil.getObject(redisTemplate, MyEnum.ACCESS_TOKEN_KEY.getMessage(), String.class);
                if (StringUtils.isEmpty(access_token)) {
                    String[] wxParam = getWxParam();
                    String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                            +wxParam[1]+"&secret="+wxParam[2];
                    for (int i=0; i<5; i++) {
                        JSONObject jsonObject = new RestTemplate().getForObject(url, JSONObject.class);
                        if (jsonObject != null) access_token = jsonObject.getString(MyEnum.ACCESS_TOKEN_KEY.getMessage());
                        if (StringUtils.isNotBlank(access_token)) break;
                    }
                    if (StringUtils.isNotBlank(access_token)) RedisUtil.setObjectExpire(redisTemplate,
                            MyEnum.ACCESS_TOKEN_KEY.getMessage(), access_token, 7000, TimeUnit.SECONDS);
                }
            } finally {
                rLock.unlock();
            }
        }
        return access_token;
    }

    public String getAccessTokenNow() {
        String[] wxParam = getWxParam();
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                +wxParam[1]+"&secret="+wxParam[2];
        String access_token = null;
        for (int i=0; i<5; i++) {
            JSONObject jsonObject = new RestTemplate().getForObject(url, JSONObject.class);
            if (jsonObject == null) continue;
            access_token = jsonObject.getString(MyEnum.ACCESS_TOKEN_KEY.getMessage());
            if (StringUtils.isNotBlank(access_token)) break;
        }
        return access_token;
    }

    public Boolean msgSecCheck (String content) {
        String accessToken = getAccessTokenFromRedis();
        String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token="+accessToken;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HashMap<String, String> param = new HashMap<>();
        param.put("content", content);

        HttpEntity<HashMap<String, String>> httpEntity = new HttpEntity<>(param, headers);
        JSONObject jsonObject = new RestTemplate().postForObject(url, httpEntity, JSONObject.class);
        if (jsonObject == null) return false;
        return (Integer) jsonObject.get("errcode") == 0;
    }

    public Boolean imgSecCheck(String pics) {
        String accessToken = getAccessTokenFromRedis();
        String url = "https://api.weixin.qq.com/wxa/img_sec_check?access_token="+accessToken;
        List<Integer> errcodes = Arrays.asList(pics.split(",")).parallelStream().map(picUrl -> {
            InputStream inputStream = null;
            ByteArrayOutputStream outStream = null;
            try {
                if (StringUtils.isEmpty(picUrl)) return 87014;
                URLConnection connection = new URL(picUrl).openConnection();
                inputStream = connection.getInputStream();
                outStream = new ByteArrayOutputStream();
                byte[] bytes = new byte[1024];
                int len;
                while ((len = inputStream.read(bytes)) > 0) outStream.write(bytes, 0, len);

                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                HttpEntity<byte[]> requestEntity = new HttpEntity<>(outStream.toByteArray(), headers);
                JSONObject jsonObject = JSON.parseObject(new RestTemplate().postForObject(url, requestEntity, String.class));
                return (Integer) jsonObject.get("errcode");
            } catch (IOException e) {
                e.printStackTrace();
                return 87014;
            } finally {
                try {
                    if (inputStream != null) inputStream.close();
                    if (outStream != null) outStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).collect(Collectors.toList());
        return ! errcodes.parallelStream().anyMatch(errcode -> errcode == 87014);
    }

    public String getWxAcode(String amUuId, Integer reCall) {
        if (reCall >= 5) return null;
        String accessToken = getAccessTokenFromRedis();
        if (StringUtils.isBlank(accessToken)) return null;
        String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+accessToken;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HashMap<String, String> param = new HashMap<>();
        param.put("scene", amUuId);
        param.put("page", "pages/index/index");
        HttpEntity<HashMap<String, String>> httpEntity3 = new HttpEntity<>(param, headers);
        ResponseEntity<Resource> responseEntity = new RestTemplate().postForEntity(url, httpEntity3, Resource.class);
        HttpHeaders responseHeaders = responseEntity.getHeaders();
        List<String> contentTypes = responseHeaders.get("Content-Type");
        if (CollectionUtils.isNotEmpty(contentTypes)) {
            if (! contentTypes.get(0).equals("image/jpeg")) {
                redisTemplate.delete(MyEnum.ACCESS_TOKEN_KEY.getMessage());
                return getWxAcode(amUuId, reCall+1);
            }
        } else return null;

        // 成功获取危险小程序二维码
        InputStream inputStream = null;
        try {
            Resource body = responseEntity.getBody();
            if (body != null) inputStream = body.getInputStream();
            return ossUtil.upload(String.format("%s-%s.png", getWxParam()[0], amUuId), inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (inputStream != null) inputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
